package cn.com.yang.thread;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 多线程处理单个文件
 * TODO
 * @author yangyijin
 * @since 2024年5月20日-上午10:38:41
 */
public class MultiDownFile {
	public static void main(String[] args) {
		String origin_path = "http://ip:port/xx.docx";
		String downPath ="F:\\使用文档\\doc文件\\面试题准备_copy.docx";
		int THREAD_COUNT=10;
		downLoadFile(origin_path,downPath,THREAD_COUNT);
	}

	/**
	 * 
	 * @param origin_path
	 * @param downPath
	 * @param threadNum 
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	private static void downLoadFile(String origin_path, String downPath,int threadNum) {
		//1.获取原始文件大小
		File file = new File(origin_path);
		long size = file.length();
		long part = size / threadNum;
		List<FileFragment> list = new ArrayList();
		for(int i=0;i<threadNum;i++) {
			long start = i*part;
			long end = (i==threadNum-1)?size-1:start+part-1;
			list.add(new FileFragment(start,end,i));
		}
		//2.多线程处理
		ExecutorService executorService = Executors.newFixedThreadPool(threadNum);
		for(FileFragment p : list) {
			executorService.submit(()->downPart(origin_path,p,downPath,part));
		}
		executorService.shutdown();
		System.out.println("文件下载成功");
	}

	/**
	 * 片段下载
	 * @param origin_path
	 * @param p
	 * @param downPath
	 * @return
	 */
	private static void downPart(String origin_path, FileFragment part, String downPath,long frag) {
		try(RandomAccessFile raf = new RandomAccessFile(downPath,"rw") ){
			raf.seek(part.getStart());
			//如果是网络请求
			URL url = new URL(origin_path);
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			conn.setRequestProperty("Range", "bytes="+part.getStart()+"-"+part.getEnd());
			conn.connect();
			
			try(InputStream io = conn.getInputStream();
					BufferedInputStream buf = new BufferedInputStream(io);
					FileOutputStream fos = new FileOutputStream(downPath,true)){//表示追加
				byte[] bytes = new byte[4096];//4k
				int hasRread=0;
				while((hasRread=buf.read(bytes))!=-1) {
					fos.write(bytes,0,hasRread);
				}
				System.out.println("部件"+part.getIndex()+"下载成功");
			}
		}catch(Exception ex) {
			ex.printStackTrace();
		}
		
	}
}
class FileFragment {
	long start;
	long end;
	int index;
	
	public FileFragment(long start, long end, int index) {
		super();
		this.start = start;
		this.end = end;
		this.index = index;
		
	}
	/**
	 * @return the start
	 */
	public long getStart() {
		return start;
	}
	/**
	 * @param start the start to set
	 */
	public void setStart(long start) {
		this.start = start;
	}
	/**
	 * @return the end
	 */
	public long getEnd() {
		return end;
	}
	/**
	 * @param end the end to set
	 */
	public void setEnd(long end) {
		this.end = end;
	}
	/**
	 * @return the index
	 */
	public int getIndex() {
		return index;
	}
	/**
	 * @param index the index to set
	 */
	public void setIndex(int index) {
		this.index = index;
	}
	
}
